using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.IO;
using System.Diagnostics;

namespace QuickLaunch
{
    public enum ShowCommands : int
    {
        SW_HIDE = 0,
        SW_SHOWNORMAL = 1,
        SW_NORMAL = 1,
        SW_SHOWMINIMIZED = 2,
        SW_SHOWMAXIMIZED = 3,
        SW_MAXIMIZE = 3,
        SW_SHOWNOACTIVATE = 4,
        SW_SHOW = 5,
        SW_MINIMIZE = 6,
        SW_SHOWMINNOACTIVE = 7,
        SW_SHOWNA = 8,
        SW_RESTORE = 9,
        SW_SHOWDEFAULT = 10,
        SW_FORCEMINIMIZE = 11,
        SW_MAX = 11
    }

    public class Shell
    {
        [DllImport("shell32.dll")]
        static extern IntPtr ShellExecute(
            IntPtr hwnd,
            string lpOperation,
            string lpFile,
            string lpParameters,
            string lpDirectory,
            ShowCommands nShowCmd);

        public const string OpenFile = "open";
        public const string EditFile = "edit";
        public const string ExploreFolder = "explore";
        public const string FindInFolder = "find";
        public const string PrintFile = "print";

        public static bool Execute(string fileName, string verb, string param)
        {
            // 1. detect if the target file is a console application
            string workdir = FileNameHelper.GetFileDirectory(fileName);
            bool useShell = true;
            if (IsConsoleApplication(fileName))
            {
                param = String.Format("/k \"{0} {1}\"", fileName, param);
                fileName = "cmd.exe";
                useShell = false;
            }
            Process proc = new Process();
            proc.StartInfo.FileName = fileName;
            proc.StartInfo.Arguments = param;
            proc.StartInfo.WorkingDirectory = workdir;
            proc.StartInfo.UseShellExecute = useShell;
            return proc.Start();
            //return ((int)ShellExecute(IntPtr.Zero, verb, fileName,
            //    param, workdir, ShowCommands.SW_NORMAL) > 32) ? true : false;
        }

        public static bool IsConsoleApplication(string fileName)
        {
            // check if the file exists
            if (!File.Exists(fileName))
                return false;
            using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read))
            {
                try
                {
                    using (BinaryReader binReader = new BinaryReader(fs))
                    {
                        try
                        {
                            fs.Position = 0x3C; //PE Header start offset
                            uint headerOffset = binReader.ReadUInt32();
                            //check if the offset is invalid
                            if (headerOffset > fs.Length - 5)
                                throw new Exception("Invalid Image Format");

                            fs.Position = headerOffset;
                            //read the PE file signature
                            uint sig = binReader.ReadUInt32();
                            if (sig != 0x00004550) //PE00
                                throw new Exception("Invalid Image Format");

                            fs.Position = headerOffset + 0x18 + 0x44;
                            UInt16 exeType = binReader.ReadUInt16();
                            switch (exeType)
                            {
                                case 2: return false; // Windows Form application
                                case 3: return true;  // Console application
                                default: return false; // Other exe type
                            }
                        }
                        finally
                        {
                            binReader.Close();
                        }
                    }
                }
                catch
                {
                    return false;
                }
                finally
                {
                    fs.Close();
                }
            }
        }

        public static bool Execute(string fileName, string verb)
        {
            return Execute(fileName, verb, "");
        }

        public static bool Open(string fileName)
        {
            return Execute(fileName, Shell.OpenFile);
        }

        public static bool Open(string fileName, string param)
        {
            return Execute(fileName, Shell.OpenFile, param);
        }

        public static bool Edit(string fileName)
        {
            return Execute(fileName, Shell.EditFile);
        }

        public static bool Edit(string fileName, string param)
        {
            return Execute(fileName, Shell.EditFile, param);
        }
    }
}
